/*
 * Author: apleilx
 * Created on 2015年9月3日, 上午9:59
 */

#ifndef __PROG_GROUP_H
#define __PROG_GROUP_H

#include "stdint.h"
#include "mytype.h"

#ifdef __cplusplus
extern "C"
{
#endif

/*******************************************************************************
 * @brief: API 错误代码
 ******************************************************************************/
#define PG_ERR_NONE 0
#define PG_ERR_TAB_FULL -1
#define PG_ERR_PHY_REUSE -2
#define PG_ERR_SEG_REUSE -3
#define PG_ERR_PHY_NOUSE -4
#define PG_ERR_SEG_NOUSE -5
#define PG_ERR_GROUP_NOUSE -6
#define PG_ERR_SUB_FULL -7
#define PG_ERR_PHY_LIMIT -8

	/*******************************************************************************
	 * @brief: 表结构
	 ******************************************************************************/
	union pg_element_str
	{
		struct
		{
			ii8 group; // 所在分组
			ii8 sub;   // 分组内的编号
			ii16 phy;  // 物理位置
		} prog;

		ii32 info;
	};

	/*******************************************************************************
	 * @brief: 管理器结构
	 ******************************************************************************/
	struct pg_man_str
	{
		// config
		union pg_element_str *tab; // 实际tab元素数，尾项强制空白
		uu16 *phy_used_st;		   // 物理号使用状态，每位表示一个，数组长度应 > tab_size / 32 + 1
		ii16 tab_size;			   // 可用表长度
		ii8 group_max;			   // 分组最大值
		ii8 sub_max;			   // 分组内编码最大值
								   //
		char head_fix;			   // fixed head or auto sort
		char cycle;				   // cycle or line

		// back
		ii16 act_num; // 激活程序数
		int8_t err;	  // 操作错误代码

		// function 返回结果
		ii16 site; // 在tab中的位置
		union pg_element_str result;
	};

	/*******************************************************************************
	 * @brief: 初始化
	 * @param pg_man_str 控制结构
	 * @param tab 内存表
	 * @param phy_st 物理状态表
	 * @param tab_size 内存表长度
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_init(struct pg_man_str *, union pg_element_str *tab, uu16 *phy_st, ii16 tab_size);

	/*******************************************************************************
	 * @brief: 工作模式
	 * @param pg_man_str 控制结构
	 * @param head_fix 分组头部固定
	 * @param cycle 循环搜索
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_mode(struct pg_man_str *, char head_fix, char cycle);

	/*******************************************************************************
	 * @brief: 工作模式
	 * @param pg_man_str 控制结构
	 * @param group_max 分组最大值 0 - n
	 * @param sub_max 组内自编码最大值 0 - n
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_size(struct pg_man_str *, ii8 group_max, ii8 sub_max);

	/*******************************************************************************
	 * @brief: 添加段
	 * @param pg_man_str 控制结构
	 * @param group 分组
	 * @param sub 子编码
	 * @param phy 物理编号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_add(struct pg_man_str *, ii8 group, ii8 sub, ii16 phy);

	/*******************************************************************************
	 * @brief: 通过物理编码删除段
	 * @param pg_man_str 控制结构
	 * @param phy 物理编号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_del_phy(struct pg_man_str *, ii16 phy);

	/*******************************************************************************
	 * @brief: 根据组号 删除段
	 * @param pg_man_str 控制结构
	 * @param group 分组
	 * @param sub 子编码
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_del_seg(struct pg_man_str *, ii8 group, ii8 sub);

	/*******************************************************************************
	 * @brief: 搜索指定物理号所在位置
	 * @param pg_man_str 控制结构
	 * @param phy 物理编号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_phy_site(struct pg_man_str *, ii16 phy);

	/*******************************************************************************
	 * @brief: 搜素指定组号所在位置
	 * @param pg_man_str 控制结构
	 * @param group 分组
	 * @param sub 子编码
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_seg_site(struct pg_man_str *, ii8 group, ii8 sub);

	/*******************************************************************************
	 * @brief: 指定索引号下一段：一般用于按键操作板，当输入参数无效时，强制结果为首位，伴随错误标志
	 * @param pg_man_str 控制结构
	 * @param site 索引号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_next_site(struct pg_man_str *, ii16 site);

	/*******************************************************************************
	 * @brief: 指定物理号下一段：一般用于按键操作板，当输入参数无效时，强制结果为首位，伴随错误标志
	 * @param pg_man_str 控制结构
	 * @param phy 物理编号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_next_phy(struct pg_man_str *, ii16 phy);

	/*******************************************************************************
	 * @brief: 指定组号下一段：一般用于按键操作板，当输入参数无效时，强制结果为首位，伴随错误标志
	 * @param pg_man_str 控制结构
	 * @param group sub 组号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_next_seg(struct pg_man_str *, ii8 group, ii8 sub);

	/*******************************************************************************
	 * @brief: 指定索引号前一段：一般用于按键操作板，当输入参数无效时，强制结果为首位，伴随错误标志
	 * @param pg_man_str 控制结构
	 * @param site 索引号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_fore_site(struct pg_man_str *, ii16 site);

	/*******************************************************************************
	 * @brief: 指定物理号前一段：一般用于按键操作板，当输入参数无效时，强制结果为首位，伴随错误标志
	 * @param pg_man_str 控制结构
	 * @param phy 物理编号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_fore_phy(struct pg_man_str *, ii16 phy);

	/*******************************************************************************
	 * @brief: 指定组号前一段：一般用于按键操作板，当输入参数无效时，强制结果为首位，伴随错误标志
	 * @param pg_man_str 控制结构
	 * @param group  sub 组号
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_fore_seg(struct pg_man_str *, ii8 group, ii8 sub);

	/*******************************************************************************
	 * @brief: 获取指定分组首个位置：未命中时site为0
	 * @param pg_man_str 控制结构
	 * @param group  分组
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_group_site(struct pg_man_str *, ii8 group);

	/*******************************************************************************
	 * @brief: 从指定分组获取一个空闲子位置, 结果 man.sub
	 * @param pg_man_str 控制结构
	 * @param group  分组
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_gp_sapce_sub_get(struct pg_man_str *, ii8 group);

	/*******************************************************************************
	 * @brief: 搜索一个空物理块
	 * @param pg_man_str 控制结构
	 * @return 错误状态
	 ******************************************************************************/
	int8_t pg_gp_sapce_phy_get(struct pg_man_str *);

	/*******************************************************************************
	 * @brief: 获取段总数
	 * @param pg_man_str 控制结构
	 * @return 错误状态
	 ******************************************************************************/
	ii16 pg_seg_amount(struct pg_man_str *);

	/*******************************************************************************
	 * @brief: 获取指定分组激活数量
	 * @param pg_man_str 控制结构
	 * @param group  分组
	 * @return 数量
	 ******************************************************************************/
	ii16 pg_gp_seg_amount(struct pg_man_str *pg, ii8 group);

#ifdef __cplusplus
}
#endif

#endif /* __PROG_GROUP_H */
